﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public abstract class ABullet : MonoBehaviour
{

    public enum BulletType
    {
        None = 0,
        C,
        M,
        S,
        F,
        L,
        R,
    }

    public GameObject boom;
    //速度测算公式： 每帧像素(3)*帧率(60)/每单位像素(16)=11.25
    public float speed = 3f * 60f / 16f;
    public float damage = 1;
    public float hitDistance = 20;
    public BulletType type = BulletType.None;
    public bool playerBullet = false;

    [Header("调试")]
    public bool bulletR = false;

    protected Vector2 launchPosition = Vector2.zero;
    protected bool launched;

    protected Rigidbody2D rig;

    protected GameObject source;
    protected BulletType bulletType;
    protected Vector2 direction;
    protected Rect limitRect;
    protected Vector2 targetPosition;
    public bool isBulletR()
    {
        return bulletR;
    }
    public void SetBulletR(bool r)
    {
        this.bulletR = r;
    }
    public BulletType GetBulletType()
    {
        return bulletType;
    }
    public void SetBulletType(BulletType bulletType)
    {
        this.bulletType = bulletType;
    }
    public void SetSource(GameObject source)
    {
        this.source = source;
    }
    public GameObject GetSource()
    {
        return this.source;
    }

    public void Launch(Vector2 direction, float speed = 0f)
    {
        Launch(direction, Vector2.positiveInfinity, speed);
    }

    public virtual void Launch(PlayerMuzzle.Muzzle muzzle, float speed = 0f){
        
    }
    public virtual void Launch(Vector2 direction, Vector2 targetPosition, float speed = 0f)
    {
        this.targetPosition = targetPosition;
        if (targetPosition.x != float.PositiveInfinity)
        {
            Vector2 a = this.targetPosition;
            Vector2 b = transform.position;
            limitRect = new(Mathf.Min(a.x, b.x), Mathf.Min(a.y, b.y), Mathf.Abs(a.x - b.x), Mathf.Abs(a.y - b.y));
        }
        if (speed > 0f)
        {
            this.speed = speed;
        }
        gameObject.SetActive(true);
        CommonLaunch(direction);
    }

    protected abstract void Hit(GameObject target);

    protected void CommonHit(Vector3 position, GameObject target)
    {
        float damageResult = DamageTarget(target);
        if (damageResult >= 0)
        {
            this.damage -= damageResult;
            if (this.damage <= 0)
            {
                CreateBoom(position);
                rig.velocity = Vector2.zero;
                Destroy(gameObject);
            }
        }
        else
        {
            CreateBoom(position);
            rig.velocity = Vector2.zero;
            Destroy(gameObject);
        }
    }
    protected virtual void OutOfLimitRange()
    {
        CreateBoom(transform.position);
        Disappear();
    }
    protected void CommonFly()
    {
        if (launched)
        {
            Vector2 currentPosition = transform.position;
            if (targetPosition.x == float.PositiveInfinity)
            {
                if ((currentPosition - launchPosition).magnitude > hitDistance)
                {
                    Disappear();
                }
            }
            else
            {
                if (!limitRect.Contains(currentPosition))
                {
                    OutOfLimitRange();
                }
            }
        }
    }

    protected void CommonLaunch(Vector2 direction)
    {
        this.direction = direction;
        //Vector2 force = direction * (speed * (bulletR ? 1.5f : 1f));
        //rig.AddForce(force);
        rig.velocity = direction * (speed * (bulletR ? 1f + (1f / 3f) : 1f));
        launchPosition = transform.position;
        launched = true;
    }
    protected void CommonOnDestroy()
    {
    }

    //public static ABullet.BulletPositionPair[] LaunchBulletPosition(BulletType bulletType, Vector2 originPosition, Vector2 direction)
    //{
    //    BulletPositionPair[] ret;
    //    switch (bulletType)
    //    {
    //        case BulletType.S:
    //            float gapArg = 12f;
    //            int bulletCount = 5;//(int)(360/gapArg)
    //            ret = new BulletPositionPair[bulletCount];
    //            float roatArg = (ret.Length - 1) / 2f * gapArg;
    //            for (int i = 0; i < ret.Length; i++)
    //            {
    //                float arg = gapArg * i - roatArg;
    //                float argRad = arg * Mathf.Deg2Rad;
    //                float x = direction.x * Mathf.Cos(argRad) + direction.y * Mathf.Sin(argRad);
    //                float y = -direction.x * Mathf.Sin(argRad) + direction.y * Mathf.Cos(argRad);
    //                ret[i] = new BulletPositionPair()
    //                {
    //                    Position = originPosition,
    //                    Direction = new Vector2(x, y)
    //                };

    //            }
    //            break;
    //        case BulletType.L:
    //            Vector3 cross = Vector3.Cross(Vector2.right, direction);
    //            float angle = Vector2.Angle(Vector2.right, direction);
    //            angle *= cross.z;
    //            int count = 4;
    //            int offset = -4;
    //            Ray2D ray = new(originPosition, direction);
    //            ret = new BulletPositionPair[count];
    //            for (int i = offset; i < offset + count; i++)
    //            {
    //                int index = i - offset;
    //                Vector2 pos = ray.GetPoint(i);
    //                ret[index] = new BulletPositionPair()
    //                {
    //                    Position = pos,
    //                    Direction = direction,
    //                    Angle = angle
    //                };
    //            }
    //            break;
    //        default:
    //            ret = new BulletPositionPair[]{
    //             new BulletPositionPair()
    //                {
    //                    Position = originPosition,
    //                    Direction = direction
    //                }
    //            };
    //            break;

    //    }
    //    return ret;

    //}

    protected void Disappear()
    {
        Destroy(gameObject);
    }

    protected GameObject CreateBoom(Vector3 position)
    {
        return Instantiate(boom, position, Quaternion.identity);
    }

    protected float DamageTarget(GameObject target)
    {
        float ret = -1;
        if (target != null)
        {
            Damageable damageable = target.GetComponent<Damageable>();
            if (damageable != null)
            {
                ret = damageable.Damage(source==null?this.gameObject:source, this.damage);
            }
        }
        return ret;
    }

    private static Dictionary<BulletType, ISet<GameObject>> _BULLET_SET = new();
    public static void AddBullet(BulletType type, GameObject bullet)
    {
        ISet<GameObject> hashSet = _BULLET_SET.GetValueOrDefault(type, null);
        if (hashSet == null)
        {
            hashSet = new HashSet<GameObject>();
            _BULLET_SET.Add(type, hashSet);
        }
        hashSet.Add(bullet);
    }
    public static bool RemoveBullet(BulletType type, GameObject bullet)
    {
        ISet<GameObject> hashSet = _BULLET_SET.GetValueOrDefault(type, null);
        if (hashSet == null)
        {
            hashSet = new HashSet<GameObject>();
            _BULLET_SET.Add(type, hashSet);
        }
        return hashSet.Remove(bullet);
    }
    public static ISet<GameObject> GetBulletSet(BulletType type)
    {
        ISet<GameObject> ret = new HashSet<GameObject>();
        ISet<GameObject> hashSet = _BULLET_SET.GetValueOrDefault(type, null);
        if (hashSet != null)
        {
            ret.UnionWith(hashSet);
        }
        return ret;
    }
    public static void ClearBulletSet(BulletType type)
    {
        ISet<GameObject> hashSet = _BULLET_SET.GetValueOrDefault(type, null);
        if (hashSet != null)
        {
            hashSet.Clear();
        }
    }
}
